#!/usr/bin/python
# -*- coding: utf-8 -*-

# External imports
import sys

# Internal imports
import reader
import method
import cryptogram
import analysis


def agustin():
  # co-winner
  for crypto in myReader.cryptograms():
    if not (crypto.hasKey() and crypto.hasMsg()):
      continue
    alphabet = cryptogram.Alphabet(crypto.key)
    alphabet.compress(cryptogram.SpanishAlphabet())
    method.Vigenere.decrypt(crypto, alphabet)
    print crypto
    print map(alphabet.encode, crypto.key)
    print alphabet

def agustin2():
  crypto = cryptogram.Cryptogram('test',
      key=u'UN ALGORITMO DOMESTICO DE CIFRADO PUEDE RESULTAR IRROMPIBLE',
      msg=u'LFHÑQMÑHLPBSOYPRDI DZZWKNTVBXLXHHKNXQKQOLDOOLDAJÑFMCJKSXLNQCHAWCLLNÑWCIDICÑDQJUK')

  alphabet = cryptogram.Alphabet(crypto.key)
  alphabet.compressPrePost(cryptogram.SpanishAlphabet())
  method.EnigmaII.decrypt(crypto, alphabet)
  print crypto

def llamame36():
  for crypto in myReader.cryptograms():
    if not (crypto.hasKey() and crypto.hasMsg()):
      continue
    CIH, CIV, CIM = method.Llamame36.getAlphabets(crypto.key)
    method.Llamame36.decrypt(crypto, CIH, CIV, CIM)
    print crypto
    print 'CIH:', CIH
    print 'CIV:', CIV
    print 'CIM:', CIM

def JPS():
  for crypto in myReader.cryptograms():
    if not crypto.hasMsg():
      continue
    table = [
        ('O', '===-'),
        ('I', '=---'),
        ('K', '=-=-'),
        ('L', '=-=='),
        ('C', '--=-'),
        ('D', '--=='),
        ('A', '----'),
        ('===', 'R'), # =-===---= => .- .
        ('=', 'P'),
        ('-----', '  '),
        ('---', ' '),
        ('-', ''),
        ('P', '.'),
        ('R', '-')
      ]
    msg = ''.join([x[0].upper() for x in crypto.msg.split()])
    for c, v in table:
      msg = msg.replace(c, v)

    crypto.msg = msg
    method.Morse.decrypt(crypto)
    crypto.plain = crypto.plain.replace('_', ' ')
    print crypto

def preDASK1(crypto):
  byteSize = 5
  alphabet = cryptogram.DASKAlphabet()
  sortedAlphabet = cryptogram.SortedDASKAlphabet()

  for i in [i
      for i in xrange(1, len(crypto.msg) / 60)
      if len(crypto.msg) % i == 0]:
    for j in xrange(min(5, i + 1)):
      # i is key length and j is vowels
      msg = cryptogram.Bitsream(crypto.msg
          , byteSize
          , i
          , alphabet)
      msg.binarize()
      msg.rotateLeft(j)
      txt = analysis.translateSubstrings(msg.alphabetize()
          , alphabet
          , sortedAlphabet
          , i)
      blankPercent = 100.0 * txt.count('_') / len(txt)
      if blankPercent > 15.0:
        # print i, j, '%.1f%%' % blankPercent
        # print txt
        yield i, j

def DASK1():
  byteSize = 5
  alphabet = cryptogram.DASKAlphabet()
  sortedAlphabet = cryptogram.SortedDASKAlphabet()

  for crypto in myReader.cryptograms():
    if not crypto.hasMsg():
      continue

    for blockSize, vowels in preDASK1(crypto):
      msg = cryptogram.Bitsream(crypto.msg
          , byteSize
          , blockSize
          , alphabet)
      msg.binarize()
      msg.rotateLeft(vowels)
      msg.alphabetize()

      columns = [''] * blockSize
      for block in msg.getBlocks():
        for i, c in enumerate(block):
          columns[i] += c

      for i in xrange(blockSize):
        columns[i] = cryptogram.Bitsream(columns[i]
            , byteSize
            , blockSize
            , alphabet)

      rotatedKey = ''
      for column in columns:
        minimum = ('a', 3000)
        for c in str(cryptogram.DASKAlphabet()).decode('utf-8'):
          key = cryptogram.Bitsream(c
              , byteSize
              , blockSize
              , alphabet)
          result = column.XOR(key)
          result.alphabetize()
          factor = analysis.correlationFactor(result.get()
              , alphabet
              , sortedAlphabet)
          if factor < minimum[1]:
            minimum = (c, factor)

        rotatedKey += minimum[0]

      key = cryptogram.Bitsream(rotatedKey
          , byteSize
          , blockSize
          , alphabet)
      result = msg.XOR(key)
      key.rotateRight(vowels)
      print key.alphabetize()
      print result.alphabetize()

def __searchPositions(txt, letter):
  retVal = []
  for i, c in enumerate(txt):
    if c == letter:
      retVal.append(i)
  return retVal


if __name__ == '__main__':
  myReader = reader.ConfigReader()
  myReader.load('archive/ACYNOS2.txt')
  crypto = myReader.get('msg reto')
  crypto = myReader.get('msg test') # Regenta
  # crypto = myReader.get('msg 6-12') # 6-12

  alpha = cryptogram.SpanishAlphabet()
  sortedAlpha = cryptogram.SortedSpanishAlphabet()

  """
  for i in xrange(6, 13):
    results = analysis.frequencyAnalysis(crypto.msg[i/2::i])
    print i, results[0][0] * 100.0 / len(crypto.msg) \
        , results[-1][0] * 100.0 / len(crypto.msg)
  """

  import math
  pi = 3.1415926536
  s = lambda x: round(math.fmod(round(round(pi + x, 10) ** 2, 10), 1), 10)
  a = lambda x: int(round(x * 27) + 1)

  A = []
  seed = 0.2357685937
  seed = 0.3462395532 # Regenta
  # seed = 0.1994052589 # 6-12
  for i in xrange(len(crypto.msg)):
    seed = s(seed)
    A.append(a(seed))
  # print ['%02d' % n for n in A[:50]], 'Ai'

  C = [alpha.encode(c) + 1 for c in crypto.msg]
  # print ['%02d' % n for n in C[:50]], 'Pi + Ki + Ai'
  # C = [(c - a) + (c - a < 1 and 28 or 0) for c, a in zip(C, A)]
  # print ['%02d' % n for n in C[:50]], 'Pi + Ki'

  KEYLEN = len(sys.argv) > 1 and int(sys.argv[1]) or 7

  msg = ''.join(map(lambda c: alpha.decode(c - 1), C))
  partials = []
  for i in xrange(1, 29):
    partials.append(analysis.translateSubstrings(''.join(
      [a == i and c or '_'
      for a, c
      in zip(A, msg)])
        , alpha
        , sortedAlpha
        , KEYLEN))

  partial = ''.join([filter(lambda x: x != '_', S)[0]
    for S
    in zip(*partials)])
  for j in xrange(KEYLEN):
    print [l[1] for l in sorted(list(set([(c, alpha.decode(C[i * KEYLEN]), A[i * KEYLEN])
          for i, c
          in enumerate(partial[j::KEYLEN]) if c == ' ']))
          , key=lambda x: x[2])]

  for i in xrange(KEYLEN, KEYLEN + 1):
    # print i, analysis.correlationFactor(analysis.translateSubstrings(msg
    plain = analysis.translateSubstrings(partial
        , alpha
        , sortedAlpha
        , i).encode('utf-8')
    print '<space>:', len(filter(lambda c: c == ' ', plain)) * 100.0 / len(plain)

    # real = open('/home/rtrevino/tmp/regenta59.txt').read()
    # ratio = len(filter(lambda c: c[0] == c[1], zip(plain, real))) * 100.0 / len(real)
    ITERATIONS = 3
    while plain:
      line, plain = plain[:70], plain[70:]
      print line
      # line, real = real[:70], real[70:]
      # print line
      if ITERATIONS == 0:
        break
      ITERATIONS -= 1
    # print 'Ratio:', '%.2f' % ratio

